package com.example.firealarm.test;

import com.example.firealarm.constant.FireProtocolConstant;
import com.example.firealarm.protocol.FireProtocolParser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.time.LocalDateTime;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 消防报警模拟器
 * 用于模拟消防设备发送报警信息
 */
@Slf4j
@Component
public class FireAlarmSimulator implements CommandLineRunner {

    @Value("${fire-alarm.server.port:9000}")
    private int serverPort;

    @Autowired
    private FireProtocolParser protocolParser;

    private final Random random = new Random();
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    private Socket socket;
    private OutputStream outputStream;
    private InputStream inputStream;
    private int serialNumber = 1;
    
    // 可用的部件类型列表
    private final byte[] componentTypes = {
        FireProtocolConstant.ComponentType.FIRE_DETECTOR,
        FireProtocolConstant.ComponentType.MANUAL_ALARM_BUTTON,
        FireProtocolConstant.ComponentType.HYDRANT_BUTTON,
        FireProtocolConstant.ComponentType.DETECTION_CIRCUIT,
        FireProtocolConstant.ComponentType.FIRE_DISPLAY_PANEL,
        FireProtocolConstant.ComponentType.HEAT_DETECTOR,
        FireProtocolConstant.ComponentType.SMOKE_DETECTOR,
        FireProtocolConstant.ComponentType.COMPOSITE_FIRE_DETECTOR,
        FireProtocolConstant.ComponentType.UV_FLAME_DETECTOR,
        FireProtocolConstant.ComponentType.IR_FLAME_DETECTOR,
        FireProtocolConstant.ComponentType.GAS_DETECTOR,
        FireProtocolConstant.ComponentType.FIRE_PUMP,
        FireProtocolConstant.ComponentType.SPRINKLER_PUMP,
        FireProtocolConstant.ComponentType.WATER_FLOW_INDICATOR,
        FireProtocolConstant.ComponentType.SIGNAL_VALVE,
        FireProtocolConstant.ComponentType.ALARM_VALVE,
        FireProtocolConstant.ComponentType.PRESSURE_SWITCH,
        FireProtocolConstant.ComponentType.FIRE_DOOR,
        FireProtocolConstant.ComponentType.FIRE_VALVE,
        FireProtocolConstant.ComponentType.SMOKE_EXHAUST_FAN,
        FireProtocolConstant.ComponentType.FIRE_DOOR_MONITOR,
        FireProtocolConstant.ComponentType.ALARM_DEVICE
    };

    // 模拟设备信息
    private final byte deviceType = FireProtocolConstant.ControlUnitType.FIRE_ALARM_SYSTEM;
    private final String deviceAddress = "010203040506";
    private final byte serverType = 0x00; // 服务器类型
    private final String serverAddress = "000000000000"; // 服务器地址

    @Override
    public void run(String... args) {
        // 延迟5秒后启动模拟器，确保服务器已启动
        scheduler.schedule(this::startSimulator, 5, TimeUnit.SECONDS);
    }

    /**
     * 启动模拟器
     */
    private void startSimulator() {
        try {
            // 连接到服务器
            socket = new Socket("localhost", serverPort);
            outputStream = socket.getOutputStream();
            inputStream = socket.getInputStream();

            log.info("模拟器已连接到服务器");

            // 启动接收线程
            new Thread(this::receiveMessages).start();

            // 发送系统状态
            sendSystemStatus(FireProtocolConstant.SystemStatus.NORMAL);

            // 每30秒发送一次正常状态
            scheduler.scheduleAtFixedRate(() -> {
                try {
                    sendSystemStatus(FireProtocolConstant.SystemStatus.NORMAL);
                } catch (Exception e) {
                    log.error("发送正常状态异常", e);
                }
            }, 30, 30, TimeUnit.SECONDS);

            // 随机发送报警和故障事件
            scheduler.scheduleAtFixedRate(() -> {
                try {
                    // 随机决定是否发送事件
                    if (random.nextInt(10) < 3) { // 30%的概率发送事件
                        // 随机决定发送火警还是故障
                        if (random.nextBoolean()) {
                            // 发送火警
                            sendFireAlarm();

                            // 10秒后恢复正常
                            scheduler.schedule(this::sendFireAlarmRestore, 10, TimeUnit.SECONDS);
                        } else {
                            // 发送故障
                            sendFault();

                            // 15秒后恢复正常
                            scheduler.schedule(this::sendFaultRestore, 15, TimeUnit.SECONDS);
                        }
                    }
                } catch (Exception e) {
                    log.error("发送随机事件异常", e);
                }
            }, 20, 60, TimeUnit.SECONDS); // 每60秒尝试一次

        } catch (Exception e) {
            log.error("启动模拟器异常", e);
        }
    }

    /**
     * 接收服务器消息
     */
    private void receiveMessages() {
        try {
            byte[] buffer = new byte[1024];
            int bytesRead;

            while ((bytesRead = inputStream.read(buffer)) != -1) {
                // 解析接收到的消息
                byte[] data = new byte[bytesRead];
                System.arraycopy(buffer, 0, data, 0, bytesRead);
                log.info("接收到服务器响应: {}", bytesToHex(data));
            }
        } catch (Exception e) {
            log.error("接收消息异常", e);
        } finally {
            closeConnection();
        }
    }

    /**
     * 发送系统状态
     */
    private void sendSystemStatus(byte status) {
        try {
            // 构建系统状态数据
            byte[] data = new byte[13];
            data[0] = status; // 系统状态

            // 系统地址（6字节）
            for (int i = 0; i < 6; i++) {
                data[1 + i] = (byte) (0x01 + i);
            }

            // 时间（6字节）：年、月、日、时、分、秒
            LocalDateTime now = LocalDateTime.now();
            data[7] = (byte) (now.getYear() - 2000); // 年（相对于2000年）
            data[8] = (byte) now.getMonthValue();
            data[9] = (byte) now.getDayOfMonth();
            data[10] = (byte) now.getHour();
            data[11] = (byte) now.getMinute();
            data[12] = (byte) now.getSecond();

            // 构建并发送消息
            byte[] message = protocolParser.buildMessage(
                    deviceType,
                    deviceAddress,
                    serverType,
                    serverAddress,
                    serialNumber++,
                    FireProtocolConstant.CommandType.UPLOAD_SYSTEM_STATUS,
                    data
            );

            outputStream.write(message);
            outputStream.flush();

            log.info("发送系统状态: {}", status == 0 ? "正常" : status == 1 ? "火警" : status == 2 ? "故障" : "其他");
        } catch (Exception e) {
            log.error("发送系统状态异常", e);
        }
    }

    /**
     * 发送火警事件
     */
    private void sendFireAlarm() {
        try {
            // 随机选择部件类型
            byte componentType = componentTypes[random.nextInt(componentTypes.length)];

            // 构建部件状态数据
            byte[] data = new byte[14];
            data[0] = componentType; // 部件类型
            data[1] = FireProtocolConstant.ComponentStatus.FIRE_ALARM; // 部件状态：火警

            // 部件地址（6字节）
            for (int i = 0; i < 6; i++) {
                data[2 + i] = (byte) random.nextInt(256);
            }

            // 时间（6字节）：年、月、日、时、分、秒
            LocalDateTime now = LocalDateTime.now();
            data[8] = (byte) (now.getYear() - 2000); // 年（相对于2000年）
            data[9] = (byte) now.getMonthValue();
            data[10] = (byte) now.getDayOfMonth();
            data[11] = (byte) now.getHour();
            data[12] = (byte) now.getMinute();
            data[13] = (byte) now.getSecond();

            // 构建并发送消息
            byte[] message = protocolParser.buildMessage(
                    deviceType,
                    deviceAddress,
                    serverType,
                    serverAddress,
                    serialNumber++,
                    FireProtocolConstant.CommandType.UPLOAD_COMPONENT_STATUS,
                    data
            );

            outputStream.write(message);
            outputStream.flush();

            // 同时发送系统火警状态
            sendSystemStatus(FireProtocolConstant.SystemStatus.FIRE_ALARM);

            log.info("发送火警事件: 部件类型={}", componentType);
        } catch (Exception e) {
            log.error("发送火警事件异常", e);
        }
    }

    /**
     * 发送火警恢复事件
     */
    private void sendFireAlarmRestore() {
        try {
            // 随机选择部件类型
            byte componentType = componentTypes[random.nextInt(componentTypes.length)];

            // 构建部件状态数据
            byte[] data = new byte[14];
            data[0] = componentType; // 部件类型
            data[1] = FireProtocolConstant.ComponentStatus.NORMAL; // 部件状态：正常

            // 部件地址（6字节）
            for (int i = 0; i < 6; i++) {
                data[2 + i] = (byte) random.nextInt(256);
            }

            // 时间（6字节）：年、月、日、时、分、秒
            LocalDateTime now = LocalDateTime.now();
            data[8] = (byte) (now.getYear() - 2000); // 年（相对于2000年）
            data[9] = (byte) now.getMonthValue();
            data[10] = (byte) now.getDayOfMonth();
            data[11] = (byte) now.getHour();
            data[12] = (byte) now.getMinute();
            data[13] = (byte) now.getSecond();

            // 构建并发送消息
            byte[] message = protocolParser.buildMessage(
                    deviceType,
                    deviceAddress,
                    serverType,
                    serverAddress,
                    serialNumber++,
                    FireProtocolConstant.CommandType.UPLOAD_COMPONENT_STATUS,
                    data
            );

            outputStream.write(message);
            outputStream.flush();

            // 同时发送系统正常状态
            sendSystemStatus(FireProtocolConstant.SystemStatus.NORMAL);

            log.info("发送火警恢复事件: 部件类型={}", componentType);
        } catch (Exception e) {
            log.error("发送火警恢复事件异常", e);
        }
    }

    /**
     * 发送故障事件
     */
    private void sendFault() {
        try {
            // 随机选择部件类型
            byte componentType = componentTypes[random.nextInt(componentTypes.length)];

            // 构建部件状态数据
            byte[] data = new byte[14];
            data[0] = componentType; // 部件类型
            data[1] = FireProtocolConstant.ComponentStatus.FAULT; // 部件状态：故障

            // 部件地址（6字节）
            for (int i = 0; i < 6; i++) {
                data[2 + i] = (byte) random.nextInt(256);
            }

            // 时间（6字节）：年、月、日、时、分、秒
            LocalDateTime now = LocalDateTime.now();
            data[8] = (byte) (now.getYear() - 2000); // 年（相对于2000年）
            data[9] = (byte) now.getMonthValue();
            data[10] = (byte) now.getDayOfMonth();
            data[11] = (byte) now.getHour();
            data[12] = (byte) now.getMinute();
            data[13] = (byte) now.getSecond();

            // 构建并发送消息
            byte[] message = protocolParser.buildMessage(
                    deviceType,
                    deviceAddress,
                    serverType,
                    serverAddress,
                    serialNumber++,
                    FireProtocolConstant.CommandType.UPLOAD_COMPONENT_STATUS,
                    data
            );

            outputStream.write(message);
            outputStream.flush();

            // 同时发送系统故障状态
            sendSystemStatus(FireProtocolConstant.SystemStatus.FAULT);

            log.info("发送故障事件: 部件类型={}", componentType);
        } catch (Exception e) {
            log.error("发送故障事件异常", e);
        }
    }

    /**
     * 发送故障恢复事件
     */
    private void sendFaultRestore() {
        try {
            // 随机选择部件类型
            byte componentType = componentTypes[random.nextInt(componentTypes.length)];

            // 构建部件状态数据
            byte[] data = new byte[14];
            data[0] = componentType; // 部件类型
            data[1] = FireProtocolConstant.ComponentStatus.NORMAL; // 部件状态：正常

            // 部件地址（6字节）
            for (int i = 0; i < 6; i++) {
                data[2 + i] = (byte) random.nextInt(256);
            }

            // 时间（6字节）：年、月、日、时、分、秒
            LocalDateTime now = LocalDateTime.now();
            data[8] = (byte) (now.getYear() - 2000); // 年（相对于2000年）
            data[9] = (byte) now.getMonthValue();
            data[10] = (byte) now.getDayOfMonth();
            data[11] = (byte) now.getHour();
            data[12] = (byte) now.getMinute();
            data[13] = (byte) now.getSecond();

            // 构建并发送消息
            byte[] message = protocolParser.buildMessage(
                    deviceType,
                    deviceAddress,
                    serverType,
                    serverAddress,
                    serialNumber++,
                    FireProtocolConstant.CommandType.UPLOAD_COMPONENT_STATUS,
                    data
            );

            outputStream.write(message);
            outputStream.flush();

            // 同时发送系统正常状态
            sendSystemStatus(FireProtocolConstant.SystemStatus.NORMAL);

            log.info("发送故障恢复事件: 部件类型={}", componentType);
        } catch (Exception e) {
            log.error("发送故障恢复事件异常", e);
        }
    }

    /**
     * 关闭连接
     */
    private void closeConnection() {
        try {
            if (socket != null && !socket.isClosed()) {
                socket.close();
            }
        } catch (Exception e) {
            log.error("关闭连接异常", e);
        }
    }

    /**
     * 将字节数组转换为十六进制字符串
     */
    private String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X ", b));
        }
        return sb.toString();
    }
}
